﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Web.UI;
using MyLib.Data;

namespace MyLib.Web.UI {
	/// <summary>
	/// 
	/// </summary>
	[ParseChildren(true, "Items")]
	[ToolboxData("<{0}:MyCodeDataSource runat=\"server\"></{0}:MyCodeDataSource>")]
	public class MyCodeDataSource : DataSourceControl {
		/// <summary>
		/// 
		/// </summary>
		private const string DefaultCodeFileName = "~/SysCode.xml";

		private List<CodeItem> m_items;

		/// <summary>
		/// 
		/// </summary>
		[Browsable(true)]
		[Bindable(false)]
		[Category("Data")]
		[DefaultValue("")]
		public string CodeFileName {
			get {
				var obj = ViewState["CodeFileName"];

				if (obj == null) {
					return DefaultCodeFileName;
				} else {
					return (string)obj;
				}
			}

			set {
				if (string.IsNullOrWhiteSpace(value)) {
					ViewState["CodeFileName"] = "";
					return;
				}

				var fn = value.Trim();

				if (!fn.StartsWith("~/") && !System.IO.Path.IsPathRooted(fn)) {
					fn = "~/" + fn;
				}

				ViewState["CodeFileName"] = fn;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Browsable(true)]
		[Bindable(false)]
		[Category("Data")]
		[DefaultValue(0)]
		public int CategoryId {
			get {
				var obj = ViewState["CategoryId"];
				if (obj == null) {
					return 0;
				} else {
					return (int)obj;
				}
			}
			set {
				ViewState["CategoryId"] = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Browsable(true)]
		[Bindable(false)]
		[Category("Data")]
		[DefaultValue(true)]
		public bool EnableSorting {
			get {
				var obj = ViewState["EnableSorting"];
				if (obj == null) {
					return true;
				} else {
					return (bool)obj;
				}
			}
			set {
				ViewState["EnableSorting"] = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Bindable(true)]
		[Browsable(true)]
		[Category("Action")]
		[DefaultValue(false)]
		public virtual bool PrependNoneCode {
			get {
				var obj = ViewState["PrependNoneCode"];
				if (obj == null) {
					return false;
				} else {
					return (bool)obj;
				}
			}
			set {
				ViewState["PrependNoneCode"] = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Bindable(true)]
		[Browsable(true)]
		[Category("Action")]
		[DefaultValue(false)]
		public virtual bool PrependAllCode {
			get {
				var obj = ViewState["PrependAllCode"];
				if (obj == null) {
					return false;
				} else {
					return (bool)obj;
				}
			}
			set {
				ViewState["PrependAllCode"] = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Bindable(false)]
		[Browsable(true)]
		[Category("Data")]
		[MergableProperty(false)]
		[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
		[DefaultValue(null)]
		public List<CodeItem> Items {
			get {
				if (m_items == null) {
					m_items = new List<CodeItem>();

					return m_items;
				} else {
					return m_items;
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="viewName"></param>
		/// <returns></returns>
		protected override DataSourceView GetView(string viewName) {
			if (viewName.Length == 0) {
				viewName = "DefaultView";
			}

			return new MyCodeDataSourceView(this, viewName, CategoryId, PrependAllCode, PrependNoneCode);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		internal CodeRow[] GetDataTable() {
			CodeTable dt = new CodeTable();

			// Load from code file.
			if (!string.IsNullOrWhiteSpace(CodeFileName)) {
				var cp = new CodeFileProvider(Context.Request.MapPath(CodeFileName), new WebCacheProvider(Context));
				var pdt = cp.LoadDataTable();

				if (CategoryId != 0) {
					pdt
						.Where(dr => dr.CategoryId == CategoryId)
						.CopyToDataTable(dt, LoadOption.OverwriteChanges);
				}
			}

			// Load from embeded item.
			dt.BeginLoadData();

			foreach (var item in Items.Where(it => it.CategoryId == CategoryId)) {
				var row = dt.AddNewRow();
				row.CategoryId = item.CategoryId;
				row.Value = item.Value;
				row.Text = item.Text;
				row.Parent = item.Parent;
			}

			dt.EndLoadData();

			dt.AcceptChanges();

			// Create data view.
			var ret = dt.Where(dr => dr.CategoryId == CategoryId);

			if (EnableSorting) {
				ret = ret.OrderBy(dr => dr.Value);
			}

			return ret.ToArray();
		}

		/// <summary>
		/// 
		/// </summary>
		public MyCodeDataSource() {
		}
	} // end of MyCodeDataSource.

	/// <summary>
	/// 
	/// </summary>
	[ParseChildren(false)]
	public sealed class CodeItem {
		/// <summary>
		/// 
		/// </summary>
		public int CategoryId {
			get;
			set;
		}

		/// <summary>
		/// 
		/// </summary>
		public string Value {
			get;
			set;
		}

		/// <summary>
		/// 
		/// </summary>
		public string Text {
			get;
			set;
		}

		/// <summary>
		/// 
		/// </summary>
		public string Parent {
			get;
			set;
		}
	} // end of CodeItem.
}
